/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.core.session;

import io.iec.edp.caf.commons.runtime.CafEnvironment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.session.SessionRepository;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Session服务接口实现类
 *
 * @author wangyandong
 * @date 2019/12/14 15:32
 */
@Slf4j
public class CafSessionServiceImpl implements ICafSessionService {

    private CafSessionManager manager;

    public CafSessionServiceImpl(SessionRepository repo) {
        this.manager = new CafSessionManager(repo);
    }

    @Override
    public CafSession create(Integer tenantId, String userId, String language, HashMap<String, String> items, SessionType sessionType) {
        return this.manager.create(tenantId, userId, null, null, language, items, sessionType);
    }

    @Override
    public CafSession create(Integer tenantId, String userId, String userCode, String userName, String language, HashMap<String, String> items, SessionType sessionType) {
        if (log.isInfoEnabled())
            log.info("-------创建Session:{}", sessionOperateLog());
        return this.manager.create(tenantId, userId, userCode, userName, language, items, sessionType);
    }

    @Override
    public CafSession findById(String sessionId) {
        if (log.isInfoEnabled())
            log.info("-------查找Session:{},调用链={}", sessionId, sessionOperateLog());
        Assert.hasText(sessionId, "sessionId can not be null");

        //获取当前上下文session
        CafSession currentSession = this.getCurrentSession();
        if (currentSession != null && sessionId.equals(currentSession.getId()))
            return currentSession;
        return this.manager.findById(sessionId);
    }

    @Override
    public void update(CafSession session) {
        if (log.isInfoEnabled())
            log.info("-------更新Session:{},调用链={}", session.getId(), sessionOperateLog());
        this.manager.update(session);
    }

    @Override
    public void deleteById(String sessionId) {
        if (log.isInfoEnabled())
            log.info("-------删除Session:{},调用链={}", sessionId, sessionOperateLog());
        Assert.hasText(sessionId, "sessionId can not be null");

        this.manager.deleteById(sessionId);
    }

    @Override
    public boolean isExpired(String sessionId) {
        if (log.isInfoEnabled())
            log.info("-------判断Session:{}是否过期,调用链={}", sessionId, sessionOperateLog());
        Assert.hasText(sessionId, "sessionId can not be null");

        //获取当前上下文session
        CafSession currentSession = this.getCurrentSession();
        if (currentSession != null && sessionId.equals(currentSession.getId()))
            return false;
        return this.manager.isExpired(sessionId);
    }

    @Override
    public List<String> filterExpired(List<String> sessionIds) {
        if (log.isInfoEnabled())
            log.info("-------获取过期的Session列表:{},调用链={}", sessionIds, sessionOperateLog());
        Assert.notNull(sessionIds, "sessionIds can not be null");

        return this.manager.filterExpired(sessionIds);
    }

    /**
     * 获取当前上下文Session
     */
    private CafSession getCurrentSession() {
        return CafSessionContextHolder.getCurrentSession();
    }

    /**
     * 记录Session的操作日志
     */
    private String sessionOperateLog() {
        StackTraceElement[] elements = Thread.currentThread().getStackTrace();
        StringBuilder record = new StringBuilder();
        for (StackTraceElement element : elements) {
            record.append("\n").append("-------" + element.getClassName() + "." + element.getMethodName() + "(" + element.getFileName() + ":" + element.getLineNumber() + ")");
        }
        return record.toString();
    }
}
